package leak_handler

import (
	"context"
	log "github.com/sirupsen/logrus"
	"google.golang.org/grpc/peer"
	leak "qabx.net/safe-app-center/api/leak"
	"qabx.net/safe-app-center/pkg/config/constants"
	"qabx.net/safe-app-center/pkg/model"
	"qabx.net/safe-app-center/pkg/utils"
	"strconv"
	"sync"
	"time"
)

var reportServiceClient leak.ReportServiceClient

var reportDeviceQuickRecogniseServiceClient leak.ReportDeviceQuickRecogniseServiceClient

var requestId = 2000000000

// 初始化锁
var lock = new(sync.RWMutex)

func getId() int {
	lock.Lock()
	if requestId > 2999999999 {
		requestId = 2000000000
	} else {
		requestId++
	}
	lock.Unlock()
	return requestId
}

type ReportServiceServerImpl struct {
}

func (r *ReportServiceServerImpl) UPLoadLeakScanLog(ctx context.Context, devices *leak.ScanLogAllDevices) (resp *leak.LeakResponse, err error) {
	p, _ := peer.FromContext(ctx)
	id := getId()
	log.Infof("UPLoadLeakScanLog(%x)req@%s:%s", id, p.Addr.String(), devices)
	//devices = filterConfirmPort(devices)
	if len(devices.ScanLogs) <= 0 {
		log.Infof("UPLoadLeakScanLog(%x)req@%s unexist hit port", id, p.Addr.String())
		return &leak.LeakResponse{Code: 1}, nil
	}

	go saveScanData(devices)
	resp = &leak.LeakResponse{Code: 1}
	return resp, err
}

func saveScanData(devices *leak.ScanLogAllDevices) error {
	scanId := devices.ScanID
	//pppoeName := devices.PPPoEName
	//gatewayMac := devices.GatewayMac
	logs := devices.ScanLogs

	tblGateway := &model.TblGateway{
		GatewayMac: devices.GatewayMac,
		PppoeName:  devices.PPPoEName,
		AreaNo:     devices.AreaNo,
	}
	tblGateway, err := tblGateway.GetGatewayByPppoeNameAndAddGateway()
	if err != nil {
		log.Errorf("db query failed: tbl_gateway GetGatewayByMacAndAddGateway failed:%s", err.Error())
		return nil
	}

	for _, v := range logs {
		device := v.Device
		deviceMac := v.MAC
		//deviceIp := v.IPv4Add
		//deviceName := device.DType

		tblDevice := &model.TblDevice{
			DeviceMac: deviceMac,
		}
		tblDevice, err := tblDevice.GetDeviceAndAddDevice(devices.PPPoEName, tblGateway.GatewayId, tblGateway.AreaNo)
		if err != nil {
			log.Errorf("db query failed: GetDeviceAndAddDevice failed:%s", err.Error())
			return nil
		}
		deviceId := tblDevice.DeviceId

		for _, scanInfo := range device.ScanInfos {
			if scanInfo.Port <= 0 {
				continue
			}
			if scanInfo.Leak != nil && scanInfo.Leak.Confirm != nil && scanInfo.Leak.Confirm.Vulns != nil && len(scanInfo.Leak.Confirm.Vulns) > 0 {
				leakInfo := scanInfo.Leak
				vulns := leakInfo.Confirm.Vulns
				for _, vuln := range vulns {
					timeTemplate := "2006-01-02 15:04:05"
					portScanTime, _ := time.Parse(timeTemplate, strconv.Itoa(int(scanInfo.TStamp)))
					threat := &model.TblDeviceScanThreat{
						ScanId:        scanId,
						DeviceId:      deviceId,
						ScanTime:      portScanTime.String(),
						Port:          int(scanInfo.Port),
						Protocol:      scanInfo.Protocol,
						ServiceName:   scanInfo.ServiceName,
						VulnType:      vuln.VulnType,
						VulnName:      vuln.VulnName,
						VulnServerity: vuln.VulnServerity,
						VulnDesc:      vuln.VulnDescription,
						VulnSolution:  vuln.VulnSolution,
						VulnCnnvd:     vuln.VulnCnnvd,
						VulnCve:       vuln.VulnCve,
						VulnCpe:       vuln.VulnCpe,
					}
					err := threat.AddDeviceScanThreat()
					if err != nil {
						log.Errorf("db error:addDeviceScanThreat failed:%s", err.Error())
						return err
					}
				}
			} else {
				//TODO 高危端口识别信息
				//_ := model.TblDeviceScanThreat{
				//	DeviceId:    deviceId,
				//	ThreatType:  "",
				//	ThreatName:  "",
				//	ThreatDesc:  "",
				//	ScanTime:    "",
				//	Port:        int(scanInfo.Port),
				//	Protocol:    scanInfo.Protocol,
				//	ServiceName: "",
				//	BreachKey:   "",
				//}
			}
		}

	}

	return nil
}

//var releasePortMap = map[int]int{
//	22:   1,
//	23:   1,
//	53:   1,
//	135:  1,
//	139:  1,
//	445:  1,
//	3389: 1,
//}

func boolPort(devices *leak.ScanLogAllDevices) bool {
	scanLogs := devices.ScanLogs
	if scanLogs != nil {
		for _, scanLog := range scanLogs {
			device := scanLog.Device
			if device.ScanInfos != nil {
				for _, info := range device.ScanInfos {
					if utils.TTLOperator.SIsMember(constants.KEY_CONFIRM_PORT, strconv.Itoa(int(info.Port))) {
						return true
					}
				}
			}
		}
	}
	return false
}

func filterConfirmPort(devices *leak.ScanLogAllDevices) *leak.ScanLogAllDevices {
	scanLogs := devices.ScanLogs
	var scanLogList []*leak.ScanLog
	if scanLogs != nil {
		for _, scanLog := range scanLogs {
			device := scanLog.Device
			if device.ScanInfos != nil {
				var scanInfoList []*leak.ScanInfo
				for _, info := range device.ScanInfos {
					if utils.TTLOperator.SIsMember(constants.KEY_CONFIRM_PORT, strconv.Itoa(int(info.Port))) {
						scanInfoList = append(scanInfoList, info)
					}
				}
				device.ScanInfos = scanInfoList
				if len(scanInfoList) > 0 {
					scanLogList = append(scanLogList, scanLog)
				}
			}
		}
	}
	devices.ScanLogs = scanLogList
	return devices
}

type ReportDeviceQuickRecogniseServiceServer struct {
}
